import re
import numpy as np
import pandas as pd
from typing import Dict, Any, Optional, Union, List, Tuple
from datetime import datetime, timedelta
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
from system.logger import get_global_logger

def _get_logger():
    """获取日志实例，如果全局logger不存在则返回None"""
    return get_global_logger()

# 检测日志的正则表达式模式
# 匹配格式: timestamp=[...] | level=DETECTION | status=... | type=... | confidence=... | [其他字段]
LOG_PATTERN = re.compile(
    r'timestamp=\[(?P<ts>[\d\-:\. ]+)\]\s*\|\s*'
    r'level=DETECTION\s*\|\s*'
    r'status=(?P<status>\w+)\s*\|\s*'
    r'type=(?P<type>\w+)\s*\|\s*'
    r'confidence=(?P<conf>0\.\d+)'
    r'(?:\s*\|\s*(?P<others>.*))?'
)

class LogParseError(Exception):
    """
    日志解析异常
    
    当日志文件格式不正确、无法解析或读取失败时抛出此异常。
    """
    
    def __init__(self, message: str, line_number: int = None, 
                 file_path: str = None, original_error: Exception = None):
        """
        初始化日志解析异常
        
        Args:
            message: 异常描述信息
            line_number: 出错的行号
            file_path: 日志文件路径
            original_error: 原始异常对象
        """
        self.line_number = line_number
        self.file_path = file_path
        self.original_error = original_error
        
        # 构建详细的错误信息
        error_parts = [message]
        
        if file_path:
            error_parts.append(f"文件: {file_path}")
        
        if line_number:
            error_parts.append(f"行号: {line_number}")
            
        if original_error:
            error_parts.append(f"原因: {str(original_error)}")
        
        super().__init__(" | ".join(error_parts))

class DataValidationError(Exception):
    """
    数据验证异常
    
    当数据不符合预期格式、范围或约束条件时抛出此异常。
    """
    
    def __init__(self, message: str, field_name: str = None, 
                 invalid_value = None, expected_format: str = None):
        """
        初始化数据验证异常
        
        Args:
            message: 异常描述信息
            field_name: 出错的字段名
            invalid_value: 无效的值
            expected_format: 期望的格式描述
        """
        self.field_name = field_name
        self.invalid_value = invalid_value
        self.expected_format = expected_format
        
        # 构建详细的错误信息
        error_parts = [message]
        
        if field_name:
            error_parts.append(f"字段: {field_name}")
        
        if invalid_value is not None:
            error_parts.append(f"无效值: {invalid_value}")
            
        if expected_format:
            error_parts.append(f"期望格式: {expected_format}")
        
        super().__init__(" | ".join(error_parts))

def convert_numpy_types(obj: Any) -> Any:
    """
    递归转换numpy/pandas类型为Python原生类型
    
    此函数用于将包含numpy/pandas数据类型的对象转换为JSON可序列化的Python原生类型，
    便于数据传输到前端UI。
    
    Args:
        obj: 待转换的对象，可以是字典、列表、numpy类型等
        
    Returns:
        Any: 转换后的对象，所有numpy/pandas类型都被转换为Python原生类型
        
    Example:
        >>> data = {'count': np.int64(100), 'rate': np.float64(0.05)}
        >>> converted = convert_numpy_types(data)
        >>> print(type(converted['count']))  # <class 'int'>
    """
    if isinstance(obj, dict):
        return {key: convert_numpy_types(value) for key, value in obj.items()}
        
    elif isinstance(obj, (list, tuple)):
        return [convert_numpy_types(item) for item in obj]
        
    elif isinstance(obj, pd.Series):
        return convert_numpy_types(obj.to_dict())
        
    elif isinstance(obj, pd.DataFrame):
        return convert_numpy_types(obj.to_dict('records'))
        
    # numpy整数类型
    elif isinstance(obj, (np.integer, np.int8, np.int16, np.int32, np.int64,
                         np.uint8, np.uint16, np.uint32, np.uint64)):
        return int(obj)
        
    # numpy浮点类型
    elif isinstance(obj, (np.floating, np.float16, np.float32, np.float64)):
        return float(obj)
        
    # numpy布尔类型
    elif isinstance(obj, np.bool_):
        return bool(obj)
        
    # pandas时间类型
    elif isinstance(obj, (pd.Timestamp, pd.Timedelta)):
        return str(obj)
        
    # numpy数组
    elif isinstance(obj, np.ndarray):
        return convert_numpy_types(obj.tolist())
        
    # 其他类型直接返回
    else:
        return obj
    
def parse_time_range(time_range_spec: Union[str, Dict[str, Any]]) -> Tuple[Optional[datetime], Optional[datetime]]:
    """
    解析时间范围规格
    
    Args:
        time_range_spec: 时间范围规格，支持以下格式：
            - "latest_hours:24" - 最近24小时
            - "latest_days:7" - 最近7天
            - {"start": "2024-01-01", "end": "2024-01-07"} - 指定开始和结束日期
            - {"start": "2024-01-01 10:00:00", "end": "2024-01-01 18:00:00"} - 指定精确时间
            
    Returns:
        Tuple[Optional[datetime], Optional[datetime]]: (开始时间, 结束时间)
        
    Raises:
        ValueError: 当时间范围格式无效时
    """
    logger = _get_logger()
    
    try:
        # 处理字符串时间范围规格
        if isinstance(time_range_spec, str):
            # 最近 n 个小时
            if time_range_spec.startswith("latest_hours:"):
                hours = int(time_range_spec.split(":")[1])
                end_time = datetime.now()
                start_time = end_time - timedelta(hours=hours)
                if logger:
                    logger.info(f"解析最近{hours}小时", start=start_time, end=end_time)
                return start_time, end_time
                
            # 最近 n 天
            elif time_range_spec.startswith("latest_days:"):
                days = int(time_range_spec.split(":")[1])
                end_time = datetime.now()
                start_time = end_time - timedelta(days=days)
                if logger:
                    logger.info(f"解析最近{days}天", start=start_time, end=end_time)
                return start_time, end_time
                
            else:
                raise ValueError(f"不支持的字符串时间范围格式: {time_range_spec}",
                                 f"请使用 'latest_hours:n' 或 'latest_days:n' 格式")
                
        # 处理字典时间范围规格
        elif isinstance(time_range_spec, dict):
            start_str = time_range_spec.get('start')
            end_str = time_range_spec.get('end')
            
            start_time = pd.to_datetime(start_str) if start_str else None
            end_time = pd.to_datetime(end_str) if end_str else None
            
            if logger:
                logger.info("解析字典时间范围", start=start_time, end=end_time)
            
            return start_time, end_time
            
        else:
            raise ValueError(f"不支持的时间范围格式类型: {type(time_range_spec)}")
            
    except Exception as e:
        if logger:
            logger.error("时间范围解析失败", time_range_spec=str(time_range_spec), error=str(e))
        raise ValueError(f"时间范围解析失败: {e}")
